﻿using System;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Push.Model.V20160801;
using BCCommon;
using BCCommon.Enums;
using BCData.Common.DeviceInfo;
using BCDto.Common.SystemExceptionRecord;
using BCService.Common.ExceptionService;

namespace BCService.PushMessage
{
    public class AliyunPushService : IAliyunPushService
    {
        private readonly IConfiguration configuration;
        private readonly IDeviceInfoData deviceInfoData;
        private readonly ISystemExceptionRecordService systemExceptionRecordService;

        public AliyunPushService(IConfiguration configuration,
            IDeviceInfoData deviceInfoData,
            ISystemExceptionRecordService systemExceptionRecordService)
        {
            this.configuration = configuration;
            this.deviceInfoData = deviceInfoData;
            this.systemExceptionRecordService = systemExceptionRecordService;
        }

        /// <summary>
        /// 单点推送
        /// </summary>
        /// <param name="appType">APP类型</param>
        /// <param name="userId">用户ID</param>
        /// <param name="title">标题</param>
        /// <param name="body">通知的正文</param>
        /// <param name="obj">推送附加信息</param>
        /// <param name="barTypeId">通知条类型Id</param>
        /// <param name="iosMusic">IOS音乐文件</param>
        public void Unicast(AppType appType, long userId, string title, string body, object obj = null, int? barTypeId = null, string iosMusic = null)
        {
            //每次最多发送100个设备
            var deviceInfoEntities = this.deviceInfoData.GetPushTokens(appType.ToString(), userId, 30).Result;
            if (deviceInfoEntities.Count() == 1)
            {
                var deviceInfo = deviceInfoEntities.First();
                string deviceKey = deviceInfo.PushToken;
                Push(appType, title, body, new string[] { deviceKey }, (OSType)Enum.Parse(typeof(OSType), deviceInfo.OSType), obj, barTypeId, iosMusic);
            }
        }

        /// <summary>
        /// 单播
        /// </summary>
        /// <param name="appType">推送app类型</param>
        /// <param name="userIds">推送用户Id列表</param>
        /// <param name="title">推送标题</param>
        /// <param name="body">推送正文</param>
        /// <param name="obj">推送附加信息</param>
        /// <param name="barTypeId">通知条类型Id</param>
        /// <param name="iosMusic">IOS音乐文件</param>
        public void Unicast(AppType appType, long[] userIds, string title, string body, object obj = null, int? barTypeId = null, string iosMusic = null)
        {
            //每次最多发送100个设备
            var deviceInfoEntities = this.deviceInfoData.GetPushTokens(appType.ToString(), userIds, 30).Result;

            OSType[] oSTypes = new OSType[] { OSType.Android, OSType.iOS };
            foreach (OSType oSType in oSTypes)
            {
                string osTypeStr = oSType.ToString();
                double deviceCount = deviceInfoEntities.Count(p => p.OSType == osTypeStr) / 100.00D;
                int count = Convert.ToInt32(deviceCount);
                if (deviceCount - count > 0)
                {
                    count = count + 1;
                }
                for (int i = 0; i < count; i++)
                {
                    string[] array = deviceInfoEntities.Where(p => p.OSType == osTypeStr).Select(p => p.PushToken).Take(100).Skip(100 * i).ToArray();

                    Push(appType, title, body, array, oSType, obj, barTypeId, iosMusic);
                }
            }

        }

        /// <summary>
        /// 单播推送异步
        /// </summary>
        /// <param name="appType">推送app类型</param>
        /// <param name="userId">推送用户Id</param>
        /// <param name="title">推送标题</param>
        /// <param name="body">推送正文</param>
        /// <param name="obj">推送附加信息</param>
        /// <param name="barTypeId">通知条类型Id</param>
        /// <param name="iosMusic">IOS音乐文件</param>
        public void UnicastAsync(AppType appType, long userId, string title, string body, object obj = null, int? barTypeId = null, string iosMusic = null)
        {
            PerformanceTracer.InvokeAsync(delegate { Unicast(appType, userId, title, body, obj, barTypeId, iosMusic); });
        }

        /// <summary>
        /// 单播推送异步
        /// </summary>
        /// <param name="appType">推送app类型</param>
        /// <param name="userIds">推送用户Id列表</param>
        /// <param name="title">推送标题</param>
        /// <param name="body">推送正文</param>
        /// <param name="obj">推送附加信息</param>
        /// <param name="barTypeId">通知条类型Id</param>
        /// <param name="iosMusic">IOS音乐文件</param>
        public void UnicastAsync(AppType appType, long[] userIds, string title, string body, object obj = null, int? barTypeId = null, string iosMusic = null)
        {
            PerformanceTracer.InvokeAsync(delegate { Unicast(appType, userIds, title, body, obj, barTypeId, iosMusic); });
        }

        private void Push(AppType appType, string title, string body, string[] keys, OSType oSType, object obj, int? barTypeId = null, string iosMusic = null)
        {
            IClientProfile clientProfile = DefaultProfile.GetProfile("cn-hangzhou", configuration["AliyunPush:AccessKeyID"], configuration["AliyunPush:AccessKeySecret"]);
            DefaultAcsClient client = new DefaultAcsClient(clientProfile);

            PushRequest request = new PushRequest();
            if (appType == AppType.ClientApp)
            {
                if (oSType == OSType.Android)
                {
                    request.AppKey = long.Parse(configuration["AliyunPush:ClientApp:appkeyAndroid"]);
                }
                else
                {
                    request.AppKey = long.Parse(configuration["AliyunPush:ClientApp:appkeyIOS"]);
                }
            }
            if (appType == AppType.DriverApp)
            {
                if (oSType == OSType.Android)
                {
                    request.AppKey = long.Parse(configuration["AliyunPush:DriverApp:appkeyAndroid"]);
                }
                else
                {
                    request.AppKey = long.Parse(configuration["AliyunPush:DriverApp:appkeyIOS"]);
                }
            }
            if (appType == AppType.PartnerApp)
            {
                if (oSType == OSType.Android)
                {
                    request.AppKey = long.Parse(configuration["AliyunPush:PartnerApp:appkeyAndroid"]);
                }
                else
                {
                    request.AppKey = long.Parse(configuration["AliyunPush:PartnerApp:appkeyIOS"]);
                }
            }
            request.DeviceType = "ALL";//为ALL时候IOS和Android控制台必须配置，否则推送失败
            request.PushType = "NOTICE";
            request.AndroidOpenType = "APPLICATION";
#if DEBUG
            request.IOSApnsEnv = "DEV"; //DEV：表示开发环境 PRODUCT：表示生产环境
#else
            request.IOSApnsEnv = "PRODUCT";
#endif

            request.IOSMusic = iosMusic;//iOS通知声音，指定存放在app bundle或沙盒Library/Sounds目录下的音频文件名，参考：iOS推送如何设定通知声音，（若指定为空串（””），通知为静音；若不设置，默认填充default为系统提示音）
            request.Target = "DEVICE";//推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            request.TargetValue = string.Join(",", keys);////根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备一次最多100)
            request.Title = title.Length >= 20 ? title.Substring(0, 20) : title;
            request.Body = body.Length >= 60 ? body.Substring(0, 60) : body;
            request.AndroidExtParameters = JsonConvert.SerializeObject(obj);
            request.IOSExtParameters = JsonConvert.SerializeObject(obj);
            request.AndroidNotificationChannel = "1";
            if (barTypeId.HasValue)
            {
                //自定义通知样式Id，与客户端需要联调使用
                request.AndroidNotificationBarType = barTypeId.Value;
            }
            try
            {
                PushResponse response = client.GetAcsResponse(request);
            }
            catch (ServerException e)
            {
                //TODO:需要增加推送失败时的记录
                Console.WriteLine(e.ErrorCode);
                Console.WriteLine(e.ErrorMessage);
                SystemExceptionRecordDto systemExceptionRecordDto = new SystemExceptionRecordDto();
                systemExceptionRecordDto.Data = JsonConvert.SerializeObject(request);
                systemExceptionRecordDto.Name = "推送失败";
                systemExceptionRecordDto.Message = "阿里云推送时失败:" + e.ErrorCode + "\r\n" + e.ErrorMessage;
                systemExceptionRecordDto.Source = e.Source;
                systemExceptionRecordDto.StackTrace = e.StackTrace;
                systemExceptionRecordDto.HelpLink = e.HelpLink;
                systemExceptionRecordDto.HResult = e.HResult;
                systemExceptionRecordDto.InnerException = JsonConvert.SerializeObject(e.InnerException);

                this.systemExceptionRecordService.Create(systemExceptionRecordDto);
            }
            catch (ClientException e)
            {
                //TODO:需要增加推送失败时的记录
                Console.WriteLine(e.ErrorCode);
                Console.WriteLine(e.ErrorMessage);
                SystemExceptionRecordDto systemExceptionRecordDto = new SystemExceptionRecordDto();
                systemExceptionRecordDto.Data = JsonConvert.SerializeObject(request);
                systemExceptionRecordDto.Name = "推送失败";
                systemExceptionRecordDto.Message = "阿里云推送时失败:" + e.ErrorCode + "\r\n" + e.ErrorMessage;
                systemExceptionRecordDto.Source = e.Source;
                systemExceptionRecordDto.StackTrace = e.StackTrace;
                systemExceptionRecordDto.HelpLink = e.HelpLink;
                systemExceptionRecordDto.HResult = e.HResult;
                systemExceptionRecordDto.InnerException = JsonConvert.SerializeObject(e.InnerException);

                this.systemExceptionRecordService.Create(systemExceptionRecordDto);
            }
        }

        #region 推送消息模板示例
        //private void pushMessage(AppType appType, long[] userIds, string title, string body, object obj, int barType, string iosMusic)
        //{
        //    this.aliyunPushService.UnicastAsync(
        //           appType,
        //           userIds,
        //           title,
        //           body,
        //           null,
        //           //new
        //           //{
        //           //    PushScopeType = PushScopeType.Order.ToString(),
        //           //    OrderNo = order.OrderNo.ToString(),
        //           //    BusinessType = order.BusinessType.ToString(),
        //           //    Status = order.Status.ToString(),
        //           //    FromProvince = order.From.Province.Name,
        //           //    FromCity = order.From.City.Name,
        //           //    FromCounty = order.From.County.Name,
        //           //    ToProvince = order.To.Province.Name,
        //           //    ToCity = order.To.City.Name,
        //           //    ToCounty = order.To.County.Name,
        //           //},
        //           GlobalVar.ANDROID_NOTIFICATION_BAR_TYPE,
        //           iosMusic);
        //}
        #endregion
    }
}
